home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / asm_n_z.arj / SDDOS.ASM < prev    next >
Assembly Source File  |  1988-01-13  |  62KB  |  1,811 lines

  1.  
  2. CODE SEGMENT
  3.  
  4.       Org    0100
  5. Main:
  6.       Jmp    Install
  7.  
  8. ;---------------------------------------------------------------------------;
  9. ;                                                                           ;
  10. ;     Data Areas, Constants, Etc.                                           ;
  11. ;                                                                           ;
  12. ;---------------------------------------------------------------------------;
  13.  
  14. Version      Db      CR,'Switch Directory - DOS 1.0',CR,LF
  15. Copyright    Db      'Copyright (c) 1987, 1988 by Stephen M. Falatko',CR,LF
  16. FakeEOF      Db      26
  17.  
  18. Errlvl       Db      0                       ;DOS return code
  19.  
  20. ;
  21. ;  These are flags set by the command line processing
  22. ;
  23. ;
  24.  
  25. RootFlag     Db      0                  ; signal indicating default to root (0)
  26. CDFlag       Db      0                  ; signal of specific path (1)
  27. OneDeepFlag  Db      0                  ; search only current dir (1)
  28.  
  29. ;
  30. ;  This flag is set to indicate that a subdirectory has been found (ie if its
  31. ;  0 at the end then we did not find the subdirectory)
  32. ;
  33.  
  34. Done_Flag    Db      0                  ; found subdir during search
  35.  
  36. ;
  37. ;  If this flag is set then help is available if ? is entered on the
  38. ;  command line
  39. ;
  40.  
  41. HelpFlag     Db      1
  42.  
  43. ;
  44. ;  If this flag is set then we can use the internal stack feature
  45. ;
  46.  
  47. StackFlag    Db      1
  48. StackAddress Dw      ProgramEndH
  49.  
  50. ;
  51. ;  The Stack_Pointer points to the internal stack path.  This is initialized
  52. ;  to 0 and changes depending on user input.
  53. ;
  54.  
  55. Stack_Pointer Db     0
  56.  
  57. InternalStackMsg        Db CR,LF,'Internal Stack:',CR,LF,CR,LF,Stopper
  58. Numbers                 Db ' 0 - ',0
  59.                         Db ' 1 - ',0
  60.                         Db ' 2 - ',0
  61.                         Db ' 3 - ',0
  62.                         Db ' 4 - ',0
  63.                         Db ' 5 - ',0
  64.                         Db ' 6 - ',0
  65.                         Db ' 7 - ',0
  66.                         Db ' 8 - ',0
  67.                         Db ' 9 - ',0
  68.  
  69. CR_LF         Db     CR,LF,Stopper
  70.  
  71. ;
  72. ;  These variables hold the systems Ctrl-Break address so we can restore
  73. ;  it when we exit
  74. ;
  75.  
  76. CtrlBrkOff   Dw      0
  77. CtrlBrkSeg   Dw      0
  78.  
  79. ;
  80. ;  Here we will store the desired subdirectory (and drive if selected)
  81. ;  as well as the original path and drive
  82. ;
  83.  
  84. Sub_Dir      Db      63 Dup (0)              ; The sub dir we want to change to
  85.  
  86. ScratchDirStart Db 'x:\'                     ; This is a scratch area for the
  87. ScratchDir      Db 63 Dup (0)                ; GetDir function
  88.  
  89. OD   LABEL  Word
  90.  
  91. OrigDr       Db      'x:'                    ; Original drive
  92. OrigDir      Db      '\',63 Dup (0)          ; and path
  93.  
  94. RootDir      Db      'x:\',0                 ; To get vol label
  95.  
  96. Count        Dw      0                       ; Number of args on command line
  97.  
  98. ;
  99. ;  These variables are used by the search routine
  100. ;
  101.  
  102. DtaPointer   Dw      DtaAreaBegin            ; Pointer to our DTA area
  103. Direction    Db      0                       ; Flag to indicate search subdirs
  104.                                              ; of the current dir or not
  105. BackOneDir   Db      '..',0                  ; Asciiz 'filename' to backup
  106.                                              ; one directory
  107. SearchAsciiZ Db      '*.*',0                 ; Search filename
  108.  
  109.  
  110.  
  111.  
  112. Old_INT_21 LABEL Dword                       ; Storage for previous INT 21
  113.  
  114. INT_21Off       Dw ?
  115. INT_21Seg       Dw ?
  116.  
  117. FirstTime?      Db 1                         ; flag to signal first pass
  118.                                              ; through INT 21 handler
  119. Command_Addr    Dw ?                         ; segment address of command.com
  120.  
  121. ;
  122. ; We want to save the callers DS:DX in the INT 21 handler
  123. ;
  124.  
  125. Callers_DS      Dw ?                         ; caller's data segment
  126. Callers_DX      Dw ?                         ; caller's dx register
  127.  
  128. CReturn         Db 0D
  129.  
  130. CR_LFString     Db 0D,0A,'$'
  131.  
  132. ;
  133. ; Command is the string that we look for at the DOS prompt.  It must
  134. ; be 8 characters long with the empty spaces blanks.
  135. ;
  136.  
  137. Command         Db 'SD      '
  138.  
  139. ;
  140. ;     Error messages
  141. ;
  142.  
  143. NoHelp         Db  CR,LF,'ERROR - Installed without help',CR,LF,Stopper
  144. NoStack        Db  CR,LF,'ERROR - Installed without Stack feature',CR,LF,Stopper
  145.  
  146. ErrorMsgs      Db  CR,LF,'Illegal drive specifier - must be A to z',CR,LF,Stopper
  147.                Db  CR,LF,'Maximum of 64 characters on command line',CR,LF,Stopper
  148.                Db  CR,LF,'Illegal character on command line       ',CR,LF,Stopper
  149.                Db  CR,LF,'Currently in root directory             ',CR,LF,Stopper
  150.                Db  CR,LF,'Command line contains an invalid path   ',CR,LF,Stopper
  151.                Db  CR,LF,'Subdirectory Not Found                  ',CR,LF,Stopper
  152.                Db  CR,LF,'Selected stack entry is empty           ',CR,LF,Stopper
  153.  
  154.  
  155. New_INT_21:
  156.  
  157.         PUSH    ES,DS,BP,SI,DI,AX,BX,CX,DX
  158.  
  159. ;
  160. ;  Is this a request for buffered input?  If not go to next INT 21.
  161. ;
  162.  
  163.         CMP     AH,0A                   ; Function 0A (hex) ?
  164.         IF NE JMP Exit_INT_21           ; If not then let's leave ....
  165.  
  166. ;
  167. ;  Let's get the length of the original caller's buffer DS:DX points
  168. ;  to caller's buffer with the first byte holding the maximum length.
  169. ;
  170.  
  171.         MOV     BX,DX
  172.         DS MOV  CL,B [BX]
  173.  
  174. ;
  175. ;  Save DS and DX of calling program and make DS equal to CS
  176. ;
  177.  
  178.         PUSH    DS                      ; Store caller's DS
  179.         MOV     DS,CS                   ; Change DS to CS
  180.  
  181.         POP     Callers_DS              ; Pop caller's DS to Old_DS
  182.  
  183.         PUSH    DX                      ; Store caller's DX
  184.         POP     Callers_DX
  185.  
  186. ;
  187. ;  We will use our command line for a buffer so copy the max length of the
  188. ;  callers buffer to the first position of the new buffer
  189. ;
  190.         MOV     BX,080                  ; Point BX to the PSP command line
  191.         MOV     B [BX],CL               ; Store the buffer length in the
  192.                                         ; first position
  193.  
  194. ;
  195. ;  Point the BP to the SP
  196. ;
  197.  
  198.         MOV     BP,SP
  199.  
  200. ;
  201. ;  Now, if it's the first time through here then COMMAND.COM is calling and we
  202. ;  save the segment address off the stack.  By doing this we can later
  203. ;  verify if a caller is COMMAND.COM or not.
  204. ;
  205.  
  206.         TEST    FirstTime?              ; If not the first time go on
  207.         JZ      Not_First_Time
  208.  
  209.         SS MOV  BX,W [BP+4]             ; Get COMMAND.COM's segment address
  210.         MOV     Command_Addr,BX         ; Save it
  211.  
  212.         MOV     FirstTime?,0            ; Clear flag
  213.         JMP     Intercept
  214.  
  215. ;
  216. ;  If this is not the first time through then we want to see if the caller
  217. ;  is COMMAND.COM or not.
  218. ;
  219.  
  220. Not_First_Time:
  221.  
  222.         SS MOV  BX,W [BP+4]             ; Get caller's segment address
  223.         CMP     BX,Command_Addr         ; Compare it with COMMAND.COM'S
  224.         IF NE JMP Exit_INT_21           ; If its not the same go to next INT 21
  225.  
  226. ;
  227. ;  Now we know that the caller is DOS so let's get the user input into our
  228. ;  own temporary buffer so we can check it against our commands.
  229. ;
  230. ;  We begin by setting up a DOS call for buffered input.
  231. ;
  232.  
  233.  
  234. Intercept:
  235.  
  236.         MOV     DX,080                  ; Point DS:DX to our PSP
  237.         MOV     AH,0A                   ; DOS function call 0A hex
  238.         PUSHF                           ; Simulate DOS interrupt
  239.         CALL Old_INT_21
  240.  
  241. ;
  242. ;  We have performed the caller's INT 21 call, now we must see if the
  243. ;  entered command is one of ours or whether we must pass it on to COMMAND.COM
  244. ;
  245.  
  246.         PUSHF                           ; First save the flags
  247.         CLD                             ; and clear the direction flag
  248.  
  249. ;
  250. ;  To simplify our comparison we will use DOS function 29 hex, parse filename,
  251. ;  to strip leading blanks and capitalize the input string.  We will store the
  252. ;  result in the PSP FCB #1 location
  253. ;
  254.  
  255.         MOV     ES,CS                   ; Make ES equal CS
  256.         MOV     SI,082                  ; The source string starts in the PSP
  257.         MOV     DI,05C                  ; Destination is in the PSP
  258.  
  259.         MOV     AX,02901                ; Parse filename call, strip leading
  260.                                         ; seperators (blanks etc.)
  261.         PUSHF                           ; Simulate DOS interrupt
  262.         CALL Old_INT_21
  263.  
  264. ;
  265. ;  Now, we have a copy of the entered command capitalized and stripped of
  266. ;  leading blanks at offset 5D in the PSP.  The question is, is the command
  267. ;  one of ours ?
  268. ;
  269.  
  270.         PUSH    SI
  271.  
  272.         MOV     SI,OFFSET Command       ; SI points to our command
  273.         MOV     DI,05D                  ; DI points to what has been typed in
  274.  
  275.         MOV     CX,8                    ; Check 8 characters
  276.  
  277.         REPE    CMPSB
  278.  
  279.         JCXZ    Its_Ours                ; If CX is zero all characters matched
  280.  
  281.         JMP     Send_It_to_CC           ; If not then we need to put command
  282.                                         ; in COMMAND.COM's buffer.
  283. ;
  284. ;  We have found our command in the buffer so we process the request.
  285. ;  First we'll output a carriage return - line feed sequence to the
  286. ;  monitor.
  287. ;
  288.  
  289. Its_Ours:
  290.  
  291.         MOV     DX,OFFSET CR_LFString
  292.         MOV     AH,09                   ; print CRLF sequence
  293.         PUSHF
  294.         CALL   Old_INT_21
  295.  
  296. ;
  297. ;  Now we want to get back SI, which points to the first character after
  298. ;  SD on the command line.  Then we can call the main processor
  299. ;
  300.  
  301.         POP     SI
  302.  
  303.         CALL    Main_Process
  304.  
  305. ;
  306. ;  We're done so we point BP to a CR, clean the stack and go on.
  307. ;
  308.  
  309.         MOV     BP,OFFSET CReturn       ; Point BP to a carriage return
  310.                                         ; character
  311.         POPF
  312.         JMP     SITC
  313.  
  314. ;
  315. ;  Now its time to send deal with COMMAND.COM's buffer.  If we found one of
  316. ;  our commands then BP points to a CR.  Otherwise BP will point to the user's
  317. ;  command that is in our PSP at OFFSET 082 (hex).
  318. ;
  319.  
  320.  
  321. Send_It_to_CC:
  322.  
  323.         POP     SI
  324.         POPF                            ; Get flags off the stack
  325.  
  326.         MOV     BP,082                  ; Point BP to the entered data (in
  327.                                         ; our PSP)
  328.  
  329.     SITC:                               ; Entry point if we found one of our
  330.                                         ; commands
  331.  
  332.         PUSH    Callers_DS              ; Make ES equal to COMMAND.COM's DS
  333.         POP     ES                      ; that we saved
  334.  
  335.         MOV     DI,Callers_DX           ; Point DI to COMMAND.COM's DX
  336.         ADD     DI,2                    ; Move past the length specifiers
  337.  
  338.         MOV     SI,BP                   ; Point SI to BP
  339.  
  340.         MOV     AL,0                    ; Initialize counter for string length
  341.  
  342. ;
  343. ;  Now that all the bookkeeping is done we can move the string to DOS's
  344. ;  buffer.
  345. ;
  346.  
  347. Move:
  348.         MOVSB                           ; Move byte
  349.  
  350.         CMP     B [SI-1],0D             ; Last character moved a CR ?
  351.         JE      Finished_Move           ; If so we are done
  352.  
  353.         INC     AL                      ; Otherwise increment counter
  354.         JMP Short Move                  ; and continue
  355.  
  356. ;
  357. ;  Our last step is to store the length of the string in COMMAND.COM's
  358. ;  buffer
  359. ;
  360.  
  361. Finished_Move:
  362.  
  363.         MOV     DI,Callers_DX           ; Point DI to COMMAND.COM's DX
  364.         INC     DI                      ; Increment it
  365.         MOV     B [DI],AL               ; Store actual string length
  366.  
  367. ;
  368. ;  Now we can leave ....
  369. ;
  370.  
  371.         POP     DX,CX,BX,AX,DI,SI,BP,DS,ES
  372.         IRET
  373.  
  374. Exit_INT_21:
  375.         POP     DX,CX,BX,AX,DI,SI,BP,DS,ES
  376.         CS JMP  Old_INT_21
  377.  
  378. ;---------------------------------------------------------------------------;
  379. ; Main_Process                                                              ;
  380. ;                                                                           ;
  381. ;     Main_Process performs all the searching and switching that is the     ;
  382. ;     heart of SDDOS                                                        ;
  383. ;                                                                           ;
  384. ;---------------------------------------------------------------------------;
  385.  
  386. Main_Process:
  387.  
  388.         CALL SetUP              ; Save current drive and path, reset drive
  389.  
  390. ;
  391. ;  We begin by determining if there are any command line arguments.
  392. ;  We look in the PSP for the command line count.
  393. ;
  394.  
  395.  
  396.         CALL StripBlanks               ; Strip any leading blanks
  397.  
  398.  
  399.         CMP     B [SI],CR               ; Next character a carriage return ?
  400.         JE      No_Parameters
  401.  
  402.  
  403.         MOV     CX,SI                   ; Get the number of characters on the
  404.         SUB     CX,082                  ; command line (from the PSP)
  405.  
  406.         MOV     AL,B [081]              ; Any characters left on command line ?
  407.         SUB     AX,CX
  408.  
  409.         CMP     AX,64                   ; more than 64 characters not allowed
  410.         JA      Got_Parameters
  411.  
  412.         MOV     Errlvl,2
  413.         JMP     Error_Found
  414. ;
  415. ;  If we find nothing then we show the current path and leave
  416. ;
  417.   No_Parameters:
  418.  
  419.         CALL ShowPath                   ; set root dir and leave
  420.  
  421.         JMP     Exit
  422. ;
  423. ;  We have found some parameters so we processes them.
  424. ;
  425.   Got_Parameters:
  426.  
  427.         CALL CommandLine
  428. ;
  429. ;  If the carry flag is set when we exit CommandLine we were unsuccessful
  430. ;
  431.         JC      Error_Found
  432. ;
  433. ;  If Done_Flag is set then we were successful, we're finished and we can leave
  434. ;
  435.         TEST    Done_Flag
  436.         IF NZ JMP Exit
  437. ;
  438. ;  If we return from CommandLine with CDFlag set that indicates that a
  439. ;  specific path has been selected and we switch to that specified path.
  440. ;  Otherwise we search for the desired subdirectory
  441. ;
  442.         TEST   CDFlag
  443.         JZ     Look_For_The_Subdir
  444.  
  445.         CALL SetPath
  446. ;
  447. ;  If the carry flag is set upon return from SetPath the path does not
  448. ;  exist and we display the not found message and return to the starting point
  449. ;  otherwise we're through and we can leave
  450. ;
  451.         IF NC JMP SHORT Exit
  452.         MOV     Errlvl,5                ; signal error type (invalid path)
  453.         JMP SHORT Error_Found
  454. ;
  455. ;  Now if CDFlag was not set we must search for the subdir.  We will begin by
  456. ;  searching the current directory (like the CD command) and then, if required,
  457. ;  we'll search the rest of the disk.
  458. ;
  459.   Look_For_The_Subdir:
  460.  
  461.         MOV     OneDeepFlag,1           ; search current level
  462.         CALL    GetDir                  ; Read the directory
  463. ;
  464. ;  Now, we reset OneDeepFlag just in case and see if we were successfull
  465. ;
  466.         MOV     OneDeepFlag,0           ; reset OneDeepFlag
  467.         TEST    Done_Flag               ; did we find it?
  468.         JNZ     Exit                    ; found it so leave
  469. ;
  470. ;  If we were not successful searching the current directory then we search
  471. ;  more of the disk.  (if rootflag is set then we search the whole disk,
  472. ;  otherwise we search only the subordinate directories.
  473. ;
  474.  
  475.         TEST    RootFlag                ; default to the root directory?
  476.         IF Z CALL No_Arg                ; if not equal set to root for search
  477.         CALL    GetDir                  ; Read the directory
  478. ;
  479. ;  If Done_Flag is set then we have been successful, otherwise we did not
  480. ;  find the desired subdirectory.
  481. ;
  482.         TEST    Done_Flag
  483.         JNZ     Exit
  484.  
  485.         MOV     Errlvl,6                ; signal error type (subdir not found)
  486.         JMP SHORT Error_Found
  487. ;
  488. ;  If we make it here we have not found the subdirectory so we tell the user
  489. ;  and return them to the starting drive:subdirectory.
  490. ;
  491.   Error_Found:
  492. ;
  493. ;  We begin by sending a message to the user
  494. ;
  495.  
  496.         CALL Error_Message
  497.  
  498. ;
  499. ;  Now we reset the drive if it has been changed.
  500. ;
  501.  
  502.         SUB     DX,DX                   ; clear DX
  503.         MOV     DL,OrigDr               ; get original drive
  504.         CMP     DL,RootDir              ; compare with current drive
  505. ;
  506. ;  If the selected directory does not match the original directory reset
  507. ;
  508.         JE     Same_Drive
  509.  
  510.         SUB     DL,'A'                  ; change DL from ascii
  511.         Set_Drive                       ; Macro...
  512. ;
  513. ;  Now we reset to our original path and leave
  514. ;
  515.   Same_Drive:
  516.  
  517.         Change_Dir OrigDr               ; Set path to original path (Macro...)
  518.  
  519. Exit:
  520.         MOV      RootFlag,0             ; reset flags for next time
  521.         MOV      CDFlag,0
  522.         MOV      OneDeepFlag,0
  523.         MOV      Done_Flag,0
  524.         MOV      Errlvl,0
  525.  
  526.         MOV      DtaPointer,offset DtaAreaBegin    ; reset pointer to our DTA
  527.  
  528.         MOV      DI,[DtaPointer]
  529.         MOV      AX,0
  530.         MOV      CX,43
  531.  
  532.    Dta_Clear:
  533.  
  534.         STOSW
  535.         LOOP     Dta_Clear
  536. ;
  537. ;  During the Setup procedure we took over the Ctrl-Break address
  538. ;  so now we restore it.
  539. ;
  540.         MOV      DX,CtrlBrkOff          ; Ctrl-Break offset
  541.         MOV      DS,CtrlBrkSeg          ; Ctrl-Break segment
  542.         MOV      AX,02523               ; set interrupt vector
  543.  
  544.         MOV      DS,CS
  545.         PUSHF
  546.         CALL Old_INT_21
  547.  
  548.         RET                             ; yes, exit with far return
  549.  
  550. ;---------------------------------------------------------------------------;
  551. ; Error_Message                                                             ;
  552. ;                                                                           ;
  553. ;     Error_Message takes the error in errlvl and displays the appropriate  ;
  554. ;     message                                                               ;
  555. ;                                                                           ;
  556. ;---------------------------------------------------------------------------;
  557.  
  558. Error_Message:
  559.  
  560.         XOR     AX,AX                   ; clear AX
  561.         MOV     DX,OFFSET ErrorMsgs     ; point to the beginning of the error msgs
  562.         MOV     AL,Errlvl               ; which error?
  563.         DEC     AX                      ; decrement for position
  564.         MOV     CX,45                   ; characters per message
  565.         MUL     CL                      ; times error type-1
  566.         ADD     DX,AX                   ; point to it
  567.         CALL    PrintS
  568.  
  569.         RET
  570.  
  571. ;---------------------------------------------------------------------------;
  572. ; No_Arg                                                                    ;
  573. ;                                                                           ;
  574. ;     No_Arg resets the current path to the root directory.                 ;
  575. ;                                                                           ;
  576. ;---------------------------------------------------------------------------;
  577.  
  578. No_Arg:
  579.                                         ; If no argument then set current
  580.         Change_Dir RootDir              ; path to root directory
  581.  
  582.         RET
  583.  
  584. ;---------------------------------------------------------------------------;
  585. ; SetUp                                                                     ;
  586. ;                                                                           ;
  587. ;     SetUp initializes some variables and resets the disk drives           ;
  588. ;                                                                           ;
  589. ;---------------------------------------------------------------------------;
  590.  
  591. SetUp:
  592.         PUSH    DX,SI,ES
  593.  
  594. ;
  595. ;  We begin with a disk reset
  596. ;
  597.         MOV     AH,0D                   ; Reset diskettes
  598.  
  599.         PUSHF
  600.         CALL Old_INT_21
  601. ;
  602. ;  Now we call DOS for the current disk drive and store the information
  603. ;  as an ascii drive specifier in several variables for future use
  604. ;
  605.         Current_Disk                    ; Get current disk  (Macro...)
  606.  
  607.         ADD     AL,'A'
  608.         MOV     OrigDr,AL               ; Save original drive letter
  609.         MOV     RootDir,AL              ;
  610.         MOV     ScratchDirStart,AL
  611. ;
  612. ;  We also want to store our current path so we can return if necessary
  613.  
  614.         MOV     DL,OrigDr               ; put original drive in DL
  615.         SUB     DL,'@'                  ; convert from ascii character
  616.         MOV     SI,OFFSET OrigDir + 1   ; the original drive
  617.         Get_Path                        ; Macro...
  618. ;
  619. ;  Our last task is to point the Ctrl+Break vector to our Not_Found code
  620. ;  so the user is left where they began if using Ctrl+Break.  But first we
  621. ;  store the current Ctrl-Brk vector so we can restore it when we leave
  622. ;
  623.         MOV    AX,03523                 ; call DOS for Ctrl-Break location
  624.  
  625.         PUSHF
  626.         CALL Old_INT_21
  627.  
  628.         MOV     CtrlBrkSeg,ES
  629.         MOV     CtrlBrkOff,BX
  630. ;
  631. ;  Now let's set up our Ctrl-Brk.
  632. ;
  633.         MOV     AX,02523                ; set Ctrl+Break vector to point
  634.         MOV     DX,OFFSET CtrlBrk       ; to our not found. This way a Ctrl+Brk
  635.                                         ; will leave us in the place we started
  636.         PUSHF
  637.         CALL Old_INT_21
  638.  
  639.         POP     ES,SI,DX
  640.         RET
  641.  
  642. ;---------------------------------------------------------------------------;
  643. ; CommandLine                                                               ;
  644. ;                                                                           ;
  645. ;     CommandLine parses the command line, looking for switches and sub-    ;
  646. ;     dir names                                                             ;
  647. ;                                                                           ;
  648. ;---------------------------------------------------------------------------;
  649.  
  650. CommandLine:
  651. ;
  652. ;  We begin by setting DI
  653. ;
  654.  
  655.         MOV     DI,OFFSET Sub_dir       ; point DI to our internal buffer for
  656.                                         ; the desired sub directory name
  657.  
  658. ;
  659. ;  We check for two switches, the internal stack switch and the enqueue switch.
  660. ;  If we find either in the first position we don't check the command line
  661. ;  for a drive specifier.
  662. ;
  663.  
  664.         CMP     B [SI],'"'
  665.         JE      Parse_Command_Line
  666.  
  667.         CMP     B [SI],'['
  668.         JE      Parse_Command_Line
  669.  
  670.         CALL Do_Drive
  671.  
  672.         CMP     Errlvl,1
  673.         IF E JMP ExitCL
  674.  
  675.         CALL StripBlanks
  676.  
  677.         CMP     B [SI],CR
  678.         JNE     Parse_Command_Line
  679.  
  680.         MOV     Done_Flag,1
  681.         JMP     ExitCL
  682.  
  683. ;
  684. ;  We've now found a drive if it has been specified and we're ready
  685. ;  to look at the rest of the command line
  686. ;
  687.   Parse_Command_Line:
  688.  
  689.         LODSB                           ; get character from command line and
  690.                                         ; put it in al
  691.  
  692.         CMP     AL,CR                   ; is it a carriage return ?
  693.         IF E JMP We_Are_Finished        ; if so we're at the end so jump on
  694.  
  695. ;
  696. ;  If we find a '.' character we must check for '..' which CD uses
  697. ;  to go back one level
  698. ;
  699.   Back_One?:
  700.  
  701.         CMP     AL,'.'
  702.         JNE     Display_Help?
  703. ;
  704. ;  We found one '.' but are there two?
  705. ;
  706.         CMP     W [SI-1],'..'           ; two periods?
  707.         JE      Go_Back_One             ; if so back one dir.
  708.  
  709. ;
  710. ;  If there are not two periods, we may have an extension on the subdir
  711. ;  name.  We check to see if the period is the first character and if it is
  712. ;  we assume an error, otherwise we process it and go on.
  713. ;
  714.  
  715.         CMP     DI,OFFSET Sub_Dir       ; is it the first character ?
  716.         IF NE JMP Process_Character     ; if not then process it
  717.  
  718.         STC                             ; otherwize - ERROR!
  719.         MOV     Errlvl,3                ; signal error type (illegal character)
  720.         JMP     ExitCL
  721.  
  722.   Go_Back_One:
  723.  
  724.         Change_Dir BackOneDir           ; change back one
  725.         JNC     Go_Back_One_Worked
  726.         MOV     Errlvl,4                ; signal error type (in root)
  727.         JMP     ExitCL                  ; leave
  728.  
  729.   Go_Back_One_Worked:
  730.  
  731.         MOV     Done_Flag,1             ; else set done_flag and leave
  732.         JMP     ExitCL                  ; do a not so nice jump to exit
  733. ;
  734. ;  If the help character (?) is the first character on the command line
  735. ;  then we display the help message and leave
  736. ;
  737.   Display_Help?:
  738.  
  739.         CMP     AL,'?'                  ; help character?
  740.         JNE     Go_Home?
  741.  
  742.         CMP     DI,OFFSET Sub_Dir       ; is it the first character ?
  743.         JNE     Do_Internal_Stack
  744. ;
  745. ;  Now that we have found the help character is help available?
  746. ;
  747.         TEST    HelpFlag                ; help info loaded ?
  748.         JNZ     Show_Help               ; yes so display it
  749. ;
  750. ;  Help not available, display message.
  751. ;
  752.         MOV     DX,OFFSET NoHelp        ; display error message and leave
  753.         CALL PrintS
  754.         MOV     Done_Flag,1
  755.         JMP     ExitCL
  756.  
  757.   Show_Help:
  758.  
  759.         MOV     DX,OFFSET Help          ; yes, let's display the help screen and
  760.         CALL PrintS                     ; then leave
  761.         MOV     Done_Flag,1
  762.         JMP     ExitCL
  763.  
  764.  
  765. ;
  766. ;  Set the path to the one indicated in Stack_Pointer ?
  767. ;
  768.  
  769.   Go_Home?:
  770.  
  771.  
  772.         CMP     AL,'@'                  ; jump 'home' ?
  773.         JNE     Do_Internal_Stack
  774.  
  775.         CMP     B [SI],CR               ; next character a carriage return ?
  776.         IF NE JMP Kill?                 ; if not assume a valid @ in path name
  777.  
  778.         MOV     AL,Stack_Pointer        ; get pointer to current location
  779.  
  780.         PUSH    AX                      ; save stack position
  781.         CALL StackBufferPos             ; get offset into stack buffer
  782.  
  783.         CMP     B [SI],0                ; empty stack position ?
  784.         IF NE JMP MoveToPath            ; if so error
  785.         POP     AX                      ; clear stack
  786.  
  787.         JMP     No_Internal_Path        ; leave
  788.  
  789. ;
  790. ;  If we find a @" on the command line then we want to kill ourselves.
  791. ;
  792.  
  793.   Kill?:
  794.  
  795.         CMP     B [SI],'"'
  796.         IF NE JMP Process_Character     ; if not assume a valid @ in path name
  797.  
  798. ;
  799. ;  Time to kill ourselves .....
  800. ;
  801.         PUSH    DS
  802.         MOV     AX,02521                ; Revector INT 21 to
  803.         MOV     DX,INT_21Off            ; the previous INT 21
  804.         MOV     DS,INT_21Seg
  805.         PUSHF
  806.         CS CALL Old_INT_21
  807.         POP     DS
  808.  
  809.         MOV     AH,049                  ; And free up our memory. (remember
  810.         MOV     ES,CS                   ; that the environment was already
  811.                                         ; deallocated during installation)
  812.         PUSHF
  813.         CALL Old_INT_21
  814.  
  815.         MOV     Done_Flag,1
  816.         JMP     ExitCL
  817.  
  818. ;
  819. ;  If we find the '"' switch we are to process the internal 'stack'.  There
  820. ;  are several possible options: 1) + go to next highest stack path (wraps)
  821. ;  2) - go to the next lowest stack path (wraps)  3) (Number) go to path
  822. ;  number..  4) (Number)= (several options) change internal stack
  823. ;
  824. ;  We first check to see if we are enqueued to CED (or PCED).  If we are
  825. ;  not then we go on.
  826. ;
  827.  
  828.   Do_Internal_Stack:
  829.  
  830.         CMP     AL,'"'                  ; Stack command switch?
  831.         IF NE JMP Search_Below?
  832.  
  833.         CMP     DI,OFFSET Sub_Dir       ; is it the first character ?
  834.         IF NE JMP ErrorIS
  835.  
  836.         TEST    StackFlag               ; stack memory available?
  837.         JNZ     Do_Stack                ; yes
  838.  
  839. ;
  840. ;  Its not available, display error message.
  841. ;
  842.  
  843.         MOV     DX,OFFSET NoStack       ; display error message and leave
  844.         CALL PrintS
  845.         MOV     Done_Flag,1
  846.         JMP     ExitCL
  847. ;
  848. ;  We have a valid '"' character so we begin by incrementing DI to point
  849. ;  to the next command line character and checking to see if it is a '+'
  850. ;
  851.   Do_Stack:
  852.  
  853.         CALL StripBlanks                ; remove leading blanks
  854.  
  855.         CMP     B [SI],'+'              ; Jump to next highest dir ?
  856.         JNE     Jump_Back?
  857.  
  858.         MOV     AL,Stack_Pointer        ; get pointer to current location
  859.  
  860. ;
  861. ;  Now, let's jump to the next highest OCCUPIED (no 0 in first position)
  862. ;  stack position
  863. ;
  864.  
  865.    J1:
  866.  
  867.         INC     AL                      ; increment stack pointer
  868.         CMP     AL,0A                   ; over 9 ?
  869.         IF E MOV AL,0                   ; if so wrap to 0
  870.         CALL StackBufferPos             ; get offset into stack buffer
  871.         CMP     B [SI],0                ; empty stack position ?
  872.         JE      J1                      ; yes - try another
  873.  
  874.         PUSH    AX                      ; save stack position
  875.         JMP     MoveToPath              ; move to the new path
  876.  
  877. ;
  878. ;  Now, let's jump to the next lowest OCCUPIED (no 0 in first position)
  879. ;  stack position
  880. ;
  881.   Jump_Back?:
  882.  
  883.         CMP     B [SI],'-'              ; jump to next lowest dir ?
  884.         JNE     Jump_To_It?
  885.  
  886.         MOV     AL,Stack_Pointer        ; get pointer to current location
  887.  
  888.    J2:
  889.  
  890.         DEC     AL                      ; decrement stack pointer
  891.         CMP     AL,0FFFF                ; less than 0 ?
  892.         IF E MOV AL,9                   ; if so wrap to 9
  893.         CALL StackBufferPos             ; get offset into stack buffer
  894.         CMP     B [SI],0                ; empty stack position ?
  895.         JE      J2                      ; yes - try another
  896.  
  897.         PUSH    AX                      ; save stack position
  898.         JMP     MoveToPath              ; move to the new path
  899.  
  900. ;
  901. ;  Are we manipulating a specific stack entry ?  If we find a 0 to 9 we are.
  902. ;
  903.  
  904.   Jump_To_It?:
  905.  
  906.         CMP     B [SI],'0'              ; Below 0 ?  If so error
  907.         IF B JMP ErrorIS
  908.  
  909.         CMP     B [SI],'9'              ; Above 9 ?  If so might be show stack
  910.         JA      Show_Stack?
  911.  
  912.         CMP     B [SI+1],'='            ; next char = ?  If so modifing entry
  913.         JE      Stack_Entry
  914.  
  915.         JMP     Set_Internal_Path       ; otherwise move to that path
  916.  
  917. ;
  918. ;  Display the internal stack if s or S selected.
  919. ;
  920.  
  921.   Show_Stack?:
  922.  
  923.         CMP     B [SI],'S'              ; S or s entered ?  If not error
  924.         IF NE CMP B [SI],'s'
  925.  
  926.         IF NE JMP ErrorIS
  927.  
  928.  
  929. ;
  930. ;  Display header and setup variables
  931. ;
  932.  
  933.         MOV     DX,OFFSET InternalStackMsg ; display header
  934.         CALL PrintS
  935.         MOV     DX,StackAddress         ; store address of stack buffer
  936.         PUSH    DX
  937.         MOV     BX,OFFSET Numbers       ; point to numbers (0 -, 1-, etc)
  938.         MOV     CX,0A                   ; loop 10 times
  939.  
  940. ;
  941. ;  This loop will print out the contents of each stack position
  942. ;
  943.  
  944.    S1:
  945.         MOV     DX,BX                   ; print the 0 -, 1 -
  946.         CALL PrintS
  947.         POP     DX                      ; get back address to stack
  948.         CALL PrintS                     ; print stack item
  949.         ADD     DX,64                   ; point to next stack item
  950.         PUSH    DX                      ; save it
  951.         MOV     DX,OFFSET CR_LF         ; print CR,LF sequence
  952.         CALL PrintS
  953.         ADD     BX,6                    ; point to next number (0 -...)
  954.         LOOP    S1
  955.  
  956.         POP     DX                      ; all done, clean up stack, set flag
  957.         MOV     Done_Flag,1             ; and leave
  958.         JMP     ExitCL
  959.  
  960.  
  961.  
  962.   Stack_Entry:
  963.  
  964.         SUB     AX,AX                   ; clear AX
  965.         MOV     AL,B [SI]               ; get number from command line
  966.         SUB     AL,030                  ; convert from ascii
  967.  
  968.         PUSH    SI                      ; get offset into stack buffer
  969.         CALL    StackBufferPos
  970.         MOV     DI,SI
  971.         POP     SI
  972.  
  973.         ADD     SI,2                    ; now point past '='
  974.  
  975.         CMP     B [SI+1],':'            ; second character drive seperator ?
  976.         JE      StoreThePath            ; If so we can go on
  977.  
  978.         MOV     AX,OD                   ; store drive specifier incase some
  979.         MOV     W [DI], AX              ; stack paths switch the drive
  980.         ADD     DI,2
  981.  
  982.         CMP     B [SI],'\'              ; path on command line ?
  983.         JE      StoreThePath            ; if so store it
  984.  
  985.         CMP     B [SI],'@'              ; get current path switch ?
  986.         JE      StoreCurrentPath
  987.  
  988.         CMP     B [SI],' '              ; blank on command line ?
  989.         IF NE JMP ErrorIS               ; if so clear entry
  990.  
  991.  
  992.         MOV     B [DI-2],0
  993.         MOV     Done_Flag,1
  994.         JMP     ExitCL
  995.  
  996. ;
  997. ;  If the @ switch is on the command line we store the current path
  998. ;  in the specified stack position.
  999. ;
  1000.  
  1001.   StoreCurrentPath:
  1002.  
  1003.         MOV     B [DI],'\'              ; start by inserting \ in buffer
  1004.         INC     DI
  1005.  
  1006.         MOV     DL,0                    ; default drive
  1007.         MOV     SI,DI
  1008.         Get_Path                        ; call DOS for the path
  1009.  
  1010.         MOV     Done_Flag,1             ; leave
  1011.         JMP     ExitCL
  1012.  
  1013.  
  1014.   StoreThePath:
  1015.         LODSB                           ; get character from command line and
  1016.                                         ; put it in al
  1017.         CMP     AL,CR
  1018.         JE      AllStored
  1019.  
  1020.         CMP     AL,'a'                  ; lowercase letter?
  1021.         IF AE XOR AL,020                ; if so make upper case
  1022. ;
  1023. ;  Now we have an upper case character let's store it in our buffer and
  1024. ;  go get the next
  1025. ;
  1026.         STOSB
  1027.         JMP SHORT StoreThePath
  1028.  
  1029.   AllStored:
  1030.         MOV     B [DI],0                ; a zero at the end of the path
  1031.         MOV     Done_Flag,1             ; to create an asciiz string
  1032.         JMP     ExitCL
  1033.  
  1034. ;
  1035. ;  Set_Internal_Path sets the path to that specified in the desired internal
  1036. ;  buffer.  If the path is empty (first position 0) an error is issued
  1037. ;
  1038.  
  1039.   Set_Internal_Path:
  1040.  
  1041.         SUB     AX,AX                   ; get number from command line and
  1042.         MOV     AL,B [SI]               ; convert from ascii
  1043.         SUB     AL,030
  1044.  
  1045.         PUSH    AX                      ; save value
  1046.         CALL StackBufferPos             ; get offset into stack buffer
  1047.  
  1048.  
  1049.         CMP     B [SI],0                ; Ascii null (no path set) ?
  1050.         JNE     MoveToPath              ; if so error
  1051.         POP     AX                      ; clear stack
  1052.         JMP SHORT No_Internal_Path      ; leave
  1053.  
  1054. ;
  1055. ;  We can now find the path and move there.  (NOTE: the + and - functions
  1056. ;  come here to set the path.
  1057. ;
  1058.  
  1059.   MoveToPath:
  1060.  
  1061.         CALL Do_Drive                   ; scan path for a drive identifier and
  1062.                                         ; set drive
  1063.  
  1064.         CMP     B [SI],0                ; anything more in path ?
  1065.         JE      ExitSIP                 ; no, so exit
  1066.  
  1067.         MOV     DX,SI                   ; change path to that specified
  1068.         MOV     AH,ChangeDir
  1069.         PUSHF
  1070.         CALL Old_INT_21
  1071.  
  1072.         JNC     ExitSIP                 ; if there is no carry (error) leave
  1073.         POP     AX                      ; clean up stack
  1074.         JMP     BadPath                 ; leave
  1075.  
  1076.  
  1077.   ExitSIP:
  1078.  
  1079.         POP     AX                      ; get back stackpointer
  1080.         MOV     Stack_Pointer,AL
  1081.         MOV     Done_Flag,1             ; signal done and leave
  1082.         JMP     ExitCL
  1083.  
  1084.   BadPath:
  1085.         STC
  1086.         MOV     Errlvl,5                ; signal error type (invalid path)
  1087.         JMP     ExitCL
  1088.  
  1089.   ErrorIS:
  1090.         STC
  1091.         MOV     B [DI-2],0
  1092.         MOV     Errlvl,3                ; signal error type (illegal character)
  1093.         JMP     ExitCL
  1094.  
  1095.  
  1096.   No_Internal_Path:
  1097.         STC
  1098.         MOV     Errlvl,7                ; signal error type (Stack entry empty)
  1099.         JMP     ExitCL
  1100.  
  1101. ;
  1102. ;  The / switch indicates that we are only to search for subdirectories of
  1103. ;  the current directory. (This was changed in version 3.0 of SD)
  1104. ;
  1105.  
  1106.   Search_Below?:
  1107.  
  1108.       CMP    AL,'/'                  ;search below (/) switch ?
  1109.       IF NE JMP Path_Specified?
  1110. ;
  1111. ;  If we find this character we want to know if its the first character of the
  1112. ;  command line or not.
  1113. ;
  1114.       CMP    DI,OFFSET Sub_Dir       ; have we stored any characters yet?
  1115.       JNE    SB_Not_First_Char
  1116. ;
  1117. ;  If it is the first we set a flag to keep us from defaulting to the
  1118. ;  root directory before we search
  1119. ;
  1120.       MOV RootFlag,1                 ; signal to search below, not reset to
  1121.       JMP SHORT Parse_Command_Line   ; root
  1122. ;
  1123. ;  Now, if its not the first character on the command line we need to
  1124. ;  do some fancy footwork.  First we need to see if a specific path
  1125. ;  has previously been signaled.
  1126. ;
  1127.   SB_Not_First_Char:
  1128.  
  1129.       TEST   CDFlag                  ; have we already seen a specific
  1130.                                      ; path on the command line?
  1131.       JZ     SB_No_Path_Yet          ; no so go on
  1132. ;
  1133. ;  A specific path has been previously selected so we make this path an
  1134. ;  asciiz string and switch to it.  Upon completion we reset DI to the
  1135. ;  begining of our command line buffer and clear the specific subdir flag.
  1136. ;
  1137.       MOV    B [DI],0                ; make current path asciiz string
  1138.       CALL SetPath                   ; change to the already specified path
  1139. ;
  1140. ;  If the carry flag is set there was an error in the path (usually it didn't
  1141. ;  exist)
  1142. ;
  1143.       JNC    SB_Not_First_Char_Done  ; if the subdir doesn't exist leave
  1144.       MOV    Errlvl,5                ; signal error type (invalid path)
  1145.       JMP    ExitCL                  ; leave
  1146. ;
  1147. ;  If the path existed then we reset DI to the beginning of our buffer,
  1148. ;  reset CDFlag and set RootFlag.
  1149. ;
  1150.   SB_Not_First_Char_Done:
  1151.  
  1152.       MOV    DI,OFFSET Sub_Dir       ; reset DI
  1153.       MOV    CDFlag,0                ; clear specific subdir flag
  1154.       MOV    RootFlag,1              ; search below, don't default to root
  1155.       JMP SHORT Parse_Command_Line   ; go get next char
  1156. ;
  1157. ;  It hasn't so this means that we search the disk for the subdir specified
  1158. ;  up till now (on the command line).  To do this we must make the name an
  1159. ;  asciiz string, search for it then specify that we don't want to default
  1160. ;  to the root directory before out next search. DI must also be reset.
  1161. ;  In doing the search we imitate the CD command by first searching the current
  1162. ;  level and then enhance it by searching the whole disk (if RootFlag set,
  1163. ;  otherwise search only below current dir)
  1164. ;
  1165.    SB_No_Path_Yet:
  1166.  
  1167.       MOV    B [DI],0                ; make current path asciiz string
  1168.       MOV    Count,DI                ; how many characters stored?
  1169.       SUB    Count,OFFSET Sub_Dir    ; we need to set this for GetDir
  1170. ;
  1171. ;  Set OneDeepFlag so we only check current directory
  1172. ;
  1173.       MOV    OneDeepFlag,1           ; start by searching current level
  1174.       CALL GetDir                    ; search for path already specified
  1175. ;
  1176. ;  Reset OneDeepFlag, check to see if we are done and if so move on
  1177. ;
  1178.       MOV    OneDeepFlag,0           ; reset the OneDeepFlag
  1179.       TEST   Done_Flag               ; see if we were successful
  1180.       JNZ    Search_A_Success        ; if so leave
  1181. ;
  1182. ;  ..otherwise re-search.  We reset to the root directory if RootFlag is set
  1183. ;
  1184.       TEST   RootFlag                ; searching only below?
  1185.       IF Z CALL No_Arg               ; set to root for search
  1186.       MOV    Count,DI                ; how many characters stored?
  1187.       SUB    Count,OFFSET Sub_Dir    ; we need to set this for GetDir
  1188.       CALL GetDir                    ; search for path already specified
  1189. ;
  1190. ;  If Done_Flag is set then we have found our directory, otherwise we set
  1191. ;  the carry flag and leave
  1192. ;
  1193.       TEST   Done_Flag               ; see if we were successful
  1194.       JZ     Search_A_Success        ; if not leave
  1195.       STC
  1196.       MOV    Errlvl,6                ; signal error type (subdir not found)
  1197.       JMP    ExitCL
  1198. ;
  1199. ;  We found the subdir, now reset Done_Flag for future use as well as DI
  1200. ;
  1201.    Search_A_Success:
  1202.  
  1203.       MOV    Done_Flag,0             ; reset Done_Flag incase of future searches
  1204.       MOV    RootFlag,1              ; search below, don't default to root
  1205.       MOV    DI,OFFSET Sub_Dir       ; reset DI
  1206.       JMP Short Parse_Command_Line
  1207. ;
  1208. ;  The \ switch indicates a specific path is specified. (i.e. no searching
  1209. ;  just switch to this path.
  1210. ;
  1211.   Path_Specified?:
  1212.  
  1213.       CMP    AL,'\'                  ; Path seperator/indicator (\) ?
  1214.       IF NE JMP Process_Character
  1215. ;
  1216. ;  If we find this flag we want to know if its the first character of the
  1217. ;  command line or not.
  1218. ;
  1219.       CMP    DI,OFFSET Sub_Dir       ; still pointing to beginning?
  1220.       JNE    PS_Not_First_Char
  1221. ;
  1222. ;  If it is the first we set a flag to indicate a specific subdir has been
  1223. ;  selected.
  1224. ;
  1225.       Change_Dir RootDir             ; make sure we are at the root dir
  1226.       MOV    CDFlag,1                ; set flag to select specific subdir
  1227. ;
  1228. ;  Strip any leading blanks.....
  1229. ;
  1230.       CALL StripBlanks
  1231. ;
  1232. ;  If all that's left is a carriage return we are done, otherwise get the next.
  1233. ;
  1234.       CMP    B [SI],CR
  1235.       IF NE JMP Short Parse_Command_Line
  1236.       MOV    Done_Flag,1
  1237.       JMP    ExitCL
  1238. ;
  1239. ;  If its not the first character we check to see if another one has already
  1240. ;  been found.
  1241. ;
  1242.   PS_Not_First_Char:
  1243.  
  1244.       TEST   CDFlag                  ; already set to look for path?
  1245.       JNZ    Already_Reading_Path    ; yes so go on
  1246. ;
  1247. ;  None has been found yet so we make the current string (in the buffer)
  1248. ;  an asciiz string and go search for the subdir it specifies.  After
  1249. ;  the search we reset DI, Done_Flag and CDFlag.
  1250. ;
  1251.       MOV    B [DI],0                ; make string asciiz
  1252. ;
  1253. ;  Set the character count and a flag to search the current level
  1254. ;
  1255.  
  1256.       MOV    Count,DI                ; how many characters stored?
  1257.       SUB    Count,OFFSET Sub_Dir    ; we need to set this for GetDir
  1258.       MOV    OneDeepFlag,1           ; start by searching current level
  1259.       CALL GetDir                    ; search for path already specified
  1260. ;
  1261. ;  Reset the OneDeepFlag and see if we found our subdir
  1262. ;
  1263.       MOV    OneDeepFlag,0           ; reset the OneDeepFlag
  1264.       TEST   Done_Flag               ; see if we were successful
  1265.       JNZ    PS_Search_A_Success     ; if not leave
  1266. ;
  1267. ;  If we didn't find the dir we check to see if we reset to the root and
  1268. ;  continue on with the search.
  1269. ;
  1270.       TEST   RootFlag                ; reseting to root ?
  1271.       IF Z CALL No_Arg               ; set to root for search if flag not set
  1272.  
  1273.       MOV    Count,DI                ; how many characters stored?
  1274.       SUB    Count,OFFSET Sub_Dir    ; we need to set this for GetDir
  1275.       CALL GetDir                    ; search for specified path
  1276. ;
  1277. ;  We have searched the desired part of the drive, now did we find anything?
  1278. ;
  1279.       TEST   Done_Flag               ; see if we were successful
  1280. ;
  1281. ;  If we did we reset the flags and continue on, otherwise leave.
  1282. ;
  1283.       JNZ    PS_Search_A_Success     ; if not leave
  1284.       STC                            ; set carry flag to signal error
  1285.       MOV    Errlvl,6                ; signal error type (subdir not found)
  1286.       JMP Short ExitCL
  1287.  
  1288.   PS_Search_A_Success:
  1289.  
  1290.       MOV    Done_Flag,0             ; reset Done_Flag incase of future searches
  1291.       MOV    DI,OFFSET Sub_Dir       ; reset DI
  1292.       MOV    CDFlag,1                ; indicate specific path
  1293.       JMP    Short Parse_Command_Line
  1294. ;
  1295. ;  If we have already seen a path seperator we continue building the
  1296. ;  desired path in our buffer.
  1297. ;
  1298.   Already_Reading_Path:
  1299.  
  1300.       STOSB
  1301.       JMP Short Parse_Command_Line   ; and get next char
  1302. ;
  1303. ;  Now we make sure the character is upper case because DOS doesn't like
  1304. ;  lower case.  There is potential for error here because these checks will
  1305. ;  pass some invalid characters (for DOS filenames).  The result is some
  1306. ;  delay before an error is found.
  1307. ;
  1308.   Process_Character:
  1309.  
  1310.       CMP    AL,'!'                  ; compare with !
  1311.       IF B JMP Parse_Command_Line    ; get next char if smaller
  1312.  
  1313.       CMP    AL,'z'                  ; compare with z
  1314.       IF A JMP Parse_Command_Line    ; get next char if bigger
  1315.  
  1316.       CMP    AL,'a'                  ; lowercase letter?
  1317.       JB     Store_The_Character     ; nope so go on
  1318.       XOR    AL,020                  ; make upper case
  1319. ;
  1320. ;  Now we have an upper case character let's store it in our buffer and
  1321. ;  go get the next
  1322. ;
  1323.   Store_The_Character:
  1324.  
  1325.       STOSb
  1326.  
  1327.       JMP Short Parse_Command_Line
  1328. ;
  1329. ;  When we get here we're done with the command line and we must make
  1330. ;  sure that we have an asciiz name in our buffer.
  1331. ;
  1332.   We_Are_Finished:
  1333.  
  1334.       MOV    Count,DI                ; how many characters stored?
  1335.       SUB    Count,OFFSET Sub_Dir
  1336. ;
  1337. ;  If count is zero we have not found anything on the command line so let's
  1338. ;  reset to the root directory and leave
  1339. ;
  1340.       CMP    Count,0
  1341.       JNE    Something_In_Buffer
  1342. ;
  1343. ;  Show the path
  1344. ;
  1345.       CALL ShowPath                  ; display the path
  1346.       MOV    Done_Flag,1             ; signal done
  1347.       JMP SHORT ExitCL               ; leave
  1348. ;
  1349. ;  We found something so let's make sure its an asciiz string
  1350. ;
  1351.   Something_In_Buffer:
  1352.  
  1353.       MOV    AL,0
  1354.       STOSB
  1355.       JMP SHORT ExitCL
  1356.  
  1357. ExitCL:
  1358.       RET
  1359.  
  1360. ;---------------------------------------------------------------------------;
  1361. ; Do_Drive                                                                  ;
  1362. ;                                                                           ;
  1363. ;     The procedure Do_Drive scans for a drive specifier.  If one is found, ;
  1364. ;     and it is different from the default drive, the drive is changed.     ;
  1365. ;                                                                           ;
  1366. ;---------------------------------------------------------------------------;
  1367.  
  1368. Do_Drive:
  1369.       PUSH   DI
  1370.  
  1371.       MOV    DI,SI
  1372.       MOV    AL,':'                  ; we'll look for a ':'
  1373.       REPNE  SCASB
  1374.  
  1375.       JNE    ExitDD                  ; if we did not find a ':' then leave
  1376. ;
  1377. ;  If we did find a drive letter then we set SI to point to the char after ':'
  1378. ;
  1379.       MOV    SI,DI                   ; now, point SI to the character following
  1380.                                      ; the ':' character
  1381. ;
  1382. ;  We now point DI to the drive letter and put it in AL
  1383. ;
  1384.       MOV    AL,B [DI-2]             ; save the drive specifier in al - again
  1385.                                      ; the segment override is needed for CED)
  1386. ;
  1387. ;  We must check the drive letter to see that it is a letter and then make sure
  1388. ;  it is capitalized
  1389. ;
  1390.       CMP    AL,'A'                  ; compare with A
  1391.       IF B JMP DriveError            ; if smaller then it is an erroneous drive
  1392.  
  1393.       CMP    AL,'z'                  ; compare with z
  1394.       IF A JMP DriveError            ; if larger then it is an erroneous drive
  1395.  
  1396.       CMP    AL,'a'                  ; lowercase letter?
  1397.       JB     New_Drive?              ; no its upper case so lets go on
  1398.       XOR    AL,020                  ; make upper case
  1399. ;
  1400. ;  Now we have an uppercase drive letter we first check to see that it is
  1401. ;  different from the original drive if its not we go on.
  1402. ;
  1403.   New_Drive?:
  1404.       CMP    OrigDr,AL
  1405.       JE     ExitDD
  1406. ;
  1407. ;  We have a different drive letter so lets store it and the change drives
  1408. ;
  1409.       MOV    RootDir,AL              ; save new drive specifier
  1410.       MOV    ScratchDirStart,AL
  1411. ;
  1412. ;  After saving we call DOS and change the drive to the desired one
  1413. ;
  1414.       SUB    DX,DX                   ; clear dx
  1415.       MOV    DL,AL                   ; must change drive to number, not ascii
  1416.       SUB    DL,'A'
  1417.       Set_Drive                      ; Macro....
  1418.       JMP    ExitDD
  1419. ;
  1420. ;  If an illegal drive was specified on the command line we come here and
  1421. ;  display and error message.  The Done_Flag is then set and we return to
  1422. ;  the main program.
  1423. ;
  1424.   DriveError:                        ; we come here if the drive specifier
  1425.                                      ; is not in A to z
  1426.       POP    DI
  1427.       MOV    Errlvl,1
  1428.       STC
  1429.  
  1430. ExitDD:
  1431.       POP    DI
  1432.       RET
  1433.  
  1434. ;---------------------------------------------------------------------------;
  1435. ; StripBlanks                                                               ;
  1436. ;                                                                           ;
  1437. ;     StripBlanks, of all things, strips leading blanks from the command    ;
  1438. ;     line.                                                                 ;
  1439. ;                                                                           ;
  1440. ;---------------------------------------------------------------------------;
  1441.  
  1442. StripBlanks:
  1443.       CMP    B [SI],' '
  1444.       IF NE RET
  1445.       INC    SI
  1446.       JMP SHORT StripBlanks
  1447.  
  1448. ;---------------------------------------------------------------------------;
  1449. ; StackBufferPos                                                            ;
  1450. ;                                                                           ;
  1451. ;     StackBufferPos determines the offset into the stack buffer for a      ;
  1452. ;     specified stack item.  The number of the item is in al.               ;
  1453. ;                                                                           ;
  1454. ;---------------------------------------------------------------------------;
  1455.  
  1456. StackBufferPos:
  1457.  
  1458.       PUSH   AX
  1459.       SUB    AH,AH
  1460.       MOV    SI,StackAddress
  1461.       MOV    CX,64
  1462.       MUL    CL
  1463.       ADD    SI,AX
  1464.       POP    AX
  1465.  
  1466.       RET
  1467.  
  1468. ;---------------------------------------------------------------------------;
  1469. ; GetDir                                                                    ;
  1470. ;                                                                           ;
  1471. ;     GetDir searches for the desired subdirectory.  The extent of the      ;
  1472. ;     search can be modified by command line switches                       ;
  1473. ;                                                                           ;
  1474. ;  Based on WHISK by Charles Wooster                                        ;
  1475. ;---------------------------------------------------------------------------;
  1476.  
  1477. GetDir:
  1478.           PUSH    SI,DI
  1479.  
  1480.           MOV     Done_Flag,0
  1481.  
  1482. ;     Find first or next subdirectory level
  1483. ;     -------------------------------------
  1484.  
  1485. NextLevel:
  1486.           MOV     DX,[DTAPointer]      ; Next nested DTA
  1487.           MOV     AH,1Ah               ; For DOS call to set DTA
  1488.           INT     21h                  ; Do it
  1489.  
  1490.           CMP     [Direction],0        ; Check if we're nesting
  1491.           JNZ     FindNextFile         ; If not, we're continuing
  1492.  
  1493.           MOV     DX,OFFSET SearchAsciiZ     ; We search for *.*
  1494.           MOV     CX,12h               ; Subdirectory attribute + hidden attrib
  1495.           MOV     AH,4Eh               ; Find first file
  1496.           INT     21h                  ;   by calling DOS
  1497.  
  1498.           JMP     Short TestMatch      ; Hop around next section
  1499. FindNextFile:
  1500.           MOV     AH,4Fh               ; Find next file
  1501.           INT     21h                  ;   by calling DOS
  1502. TestMatch:
  1503.           JC      NoMoreFiles          ; If CY flag, at end of rope
  1504.  
  1505.           MOV     BX,[DTAPointer]      ; Our find stuff is here
  1506.           TEST    B [BX + 21],10h      ; Test if directory attribute
  1507.           JZ      FindNextFile         ; If not, continue search
  1508.  
  1509.           ADD     BX,30                ; Now points to directory name
  1510.           CMP     Byte Ptr [BX],'.'    ; Ignore "." and ".." entries
  1511.           JZ      FindNextFile         ;   by continuing the search
  1512.  
  1513.           TEST    OneDeepFlag          ; looking only at this level?
  1514.           JNZ     Compare
  1515.  
  1516.           PUSH    BX                   ; save pointer to subdir name
  1517.  
  1518.           MOV     DX,BX                ; Now DX points to found dir
  1519.           MOV     AH,3Bh               ; Set up DOS function call
  1520.           INT     21h                  ; And change directory
  1521.  
  1522.           POP     BX                   ; get pointer to subdir name back
  1523.     Compare:
  1524.           SUB     CX,CX
  1525.           MOV     CX,Count
  1526.           MOV     DI, Offset Sub_Dir
  1527.           LEA     SI, BX
  1528.           REPE    CMPSB
  1529.  
  1530.           JZ      Found                ; matched up so leave
  1531.  
  1532.           TEST    OneDeepFlag
  1533.           JZ      GoOn
  1534.           MOV     [Direction],-1
  1535.           JMP SHORT NextLevel
  1536.       GoOn:
  1537.           ADD     [DtaPointer],43      ; New DTA for new level
  1538.           MOV     [Direction],0        ; I.E., Find first file
  1539.  
  1540.           JMP     NextLevel            ; All ready to cycle through
  1541.  
  1542. ;     No More Files Found -- go back to previous level
  1543. ;     ------------------------------------------------
  1544.  
  1545. NoMoreFiles:
  1546.           CMP     [DTAPointer],OFFSET DtaAreaBegin   ; See if back at start
  1547.  
  1548.           JZ      ExitGD               ; If so, that's all, folks
  1549.  
  1550.           SUB     [DTAPointer],43      ; Back one for previous
  1551.           MOV     [Direction],-1       ; I.E., will find next file
  1552.  
  1553.           MOV     DX,OFFSET BackOneDir ; The string ".."
  1554.           MOV     AH,3Bh               ; CALL to change directory
  1555.           INT     21h                  ; Change directory to father
  1556.  
  1557.           JMP     NextLevel            ; And continue the search
  1558. Found:
  1559.           TEST    OneDeepFlag
  1560.           IF Z JMP SHORT F1
  1561.  
  1562.           MOV     DX,BX                ; Now DX points to found dir
  1563.           MOV     AH,3Bh               ; Set up DOS function call
  1564.           INT     21h                  ; And change directory
  1565.       F1:
  1566.           MOV     Done_Flag,1
  1567. ExitGD:
  1568.           MOV     [Direction],0
  1569.           POP     DI,SI
  1570.           RET
  1571.  
  1572. ;---------------------------------------------------------------------------;
  1573. ; SetPath                                                                   ;
  1574. ;                                                                          ;
  1575. ;     SetPath changes to the designated path. It first checks the current  ;
  1576. ;     path and if its not the root directory, appends the desired path to   ;
  1577. ;     this directory                                                        ;
  1578. ;                                                                           ;
  1579. ;---------------------------------------------------------------------------;
  1580.  
  1581. SetPath:
  1582. ;
  1583. ;  We begin by saving SI, DI and ES.  Then we point ES to CS for the Scasb
  1584. ;  and the Stosb.  This is required in case we are enqueued to CED.
  1585. ;
  1586.       PUSH   SI,DI
  1587.       CLC
  1588. ;
  1589. ;  Our first step is to call DOS for the current path to see if we are in
  1590. ;  the root directory or not.
  1591. ;
  1592.       MOV    DL,RootDir                ; check current drive
  1593.       SUB    DL,'@'                    ; change from ascii
  1594.       MOV    SI,OFFSET ScratchDir      ; scratch buffer for path
  1595.       Get_Path                         ; Macro...
  1596. ;
  1597. ;  If we are in the root directory (the first character in ScratchDir is an
  1598. ;  ascii null) then we can go on because Sub_Dir contains a complete path
  1599. ;
  1600.  
  1601.       CMP    ScratchDir,0
  1602.       JE     SP1
  1603. ;
  1604. ;  If we are not in the root directory we must append the desired subdirectory
  1605. ;  to the end of the current directory before trying to select it.
  1606. ;
  1607.       MOV    CX,64
  1608.       MOV    DI,OFFSET ScratchDir      ; we want to find the
  1609.       MOV    AL,0                      ; end of the pathname
  1610.       REPNE  SCASB
  1611.       MOV    AL,'\'                    ; insert path seperator at the end
  1612.       DEC    DI
  1613.       STOSb
  1614.       MOV    SI,OFFSET Sub_Dir
  1615. ;
  1616. ;  We now move the desired subdirectory to the end of the current subdir.
  1617. ;
  1618.   SP2:
  1619.       LODSB
  1620.       CMP    AL,0
  1621.       JE     ExitSetP
  1622.       STOSB
  1623.       JMP SHORT SP2
  1624. ;
  1625. ;  If Sub_dir contains a complete path we move it to ScratchDir
  1626. ;
  1627.   SP1:
  1628.       MOV    DI,OFFSET ScratchDir      ; target
  1629.       MOV    SI,OFFSET Sub_Dir         ; sub dir from command line
  1630.   SP3:
  1631.       LODSB
  1632.       CMP    AL,0                      ; At the end yet ?
  1633.       JE     ExitSetP                  ; yes, gon on
  1634.       STOSB
  1635.       JMP SHORT SP3
  1636.  
  1637. ExitSetP:
  1638. ;
  1639. ;  We store the null character in AL to insure an asciiz string and set
  1640. ;  the path.
  1641. ;
  1642.       STOSB                            ; store 0 to make asciiz string
  1643.  
  1644.       Change_Dir ScratchDirStart       ; Macro...
  1645.  
  1646.       POP    DI,SI
  1647.       RET
  1648.  
  1649. ;---------------------------------------------------------------------------;
  1650. ; ShowPath                                                                  ;
  1651. ;                                                                          ;
  1652. ;     ShowPath displays the current path.                                   ;
  1653. ;                                                                           ;
  1654. ;---------------------------------------------------------------------------;
  1655.  
  1656. ShowPath:
  1657. ;
  1658. ;  We begin by saving SI, DI and ES.  Then we point ES to CS for the Scasb
  1659. ;  and the Stosb incase we are enqueued to CED.
  1660. ;
  1661.       PUSH   SI,DI
  1662. ;
  1663. ;  Our first step is to call DOS for the current path
  1664. ;
  1665.       MOV    DL,0                   ; use default drive
  1666.       MOV    SI,OFFSET ScratchDir
  1667.       Get_Path
  1668. ;
  1669. ;  Now we display the path
  1670. ;
  1671.       MOV    SI,OFFSET ScratchDirStart
  1672.  
  1673.  
  1674.  
  1675.  
  1676.   SPath1:
  1677.       LODSB
  1678.       CMP    AL,0
  1679.       JE     ExitShowP
  1680.       MOV    DL,AL
  1681.       MOV    AH,06
  1682.       PUSHF
  1683.       CALL   Old_INT_21
  1684.       JMP SHORT SPath1
  1685.  
  1686. ExitShowP:
  1687.       MOV    DL,CR                   ; print CRLF sequence
  1688.       MOV    AH,06
  1689.       PUSHF
  1690.       CALL   Old_INT_21
  1691.       MOV    DL,LF
  1692.       MOV    AH,06
  1693.       PUSHF
  1694.       CALL   Old_INT_21
  1695.  
  1696.  
  1697.       POP    DI,SI
  1698.       RET
  1699.  
  1700. ;---------------------------------------------------------------------------;
  1701. ;                                                                           ;
  1702. ;     Print String like INT 21H function 9                                  ;
  1703. ;                                                                           ;
  1704. ;  written by V. Buerg, minor mods by SM Falatko                            ;
  1705. ;                                                                           ;
  1706. ;---------------------------------------------------------------------------;
  1707.  
  1708.  
  1709. PrintS:                                      ; DX has offset to string
  1710.       PUSH   SI                      ;  ending in char x'FF'
  1711.       PUSH   BX
  1712.       PUSH   CX
  1713.       MOV    SI,DX                   ; Ptr to string text
  1714.       SUB    CX,CX                   ; Overall text length
  1715.  
  1716. PS1:  LODSB
  1717.       CMP    AL,Stopper              ; Ending hex FF?
  1718.       JE     PS9
  1719.       CMP    AL,0                    ; Ascii null?
  1720.       JE     PS9
  1721.       CMP    AL,26                   ; end of file?
  1722.       JE     PS9
  1723.       INC    CX
  1724.       JMP    Short PS1
  1725.  
  1726. PS9:
  1727.       MOV    BX,1                    ; Standard output device
  1728.       MOV    AH,40h                  ;  to write to
  1729.       PUSHF
  1730.       CALL   Old_INT_21
  1731.  
  1732.       POP    CX                      ; Recover registers
  1733.       POP    BX
  1734.       POP    SI
  1735.       RET
  1736.  
  1737. ;---------------------------------------------------------------------------;
  1738. ; CtrlBrk                                                                   ;
  1739. ;                                                                           ;
  1740. ;     CtrlBrk handles Ctrl-Breaks.  It calls a section of the code to       ;
  1741. ;     restore the original drive and path and leaves.                       ;
  1742. ;                                                                           ;
  1743. ;---------------------------------------------------------------------------;
  1744.  
  1745. CtrlBrk:
  1746.       STI
  1747.       PUSH   AX,BX,CX,DX,SI,DI,ES,DS
  1748.  
  1749.       SUB    DX,DX                   ; clear DX
  1750.       MOV    DL,OrigDr               ; get original drive
  1751.       CMP    DL,RootDir              ; compare with current drive
  1752. ;
  1753. ;  If the selected directory does not match the original directory reset
  1754. ;
  1755.       JE     Same_Drv
  1756.  
  1757.       SUB    DL,'A'                  ; change DL from ascii
  1758.       Set_Drive                      ; Macro...
  1759. ;
  1760. ;  Now we reset to our original path and leave
  1761. ;
  1762.   Same_Drv:
  1763.  
  1764.       Change_Dir OrigDr              ; Set path to original path (Macro...)
  1765.  
  1766.       POP    DS,ES,DI,SI,DX,CX,BX,AX
  1767.       STC
  1768.       RETF
  1769.  
  1770. ;----------------------------------------------------------------------------
  1771. ;
  1772. ;   This is where we will store the temporary directory information
  1773. ;
  1774.  
  1775.  
  1776. DtaAreaBegin   equ     $
  1777. DtaAreaEnd     equ     DtaAreaBegin + 10 * 43     ; Can have 10 DTAs of 43 bytes
  1778.  
  1779. ;
  1780. ;  Put the help here so that can be or not be part of memory resident code
  1781. ;  depending on user input.
  1782. ;
  1783.  
  1784.               Org DtaAreaEnd
  1785.  
  1786. Help           Db ' Usage:    [d:\....]>SD [drive][command specification]',CR,LF,CR,LF
  1787.                Db '  Commands:',CR,LF
  1788.                Db '  During startup - ',CR,LF
  1789.                Db '             with +   no help',CR,LF
  1790.                Db '             with -   no internal stack',CR,LF
  1791.                Db '             can also put configuration file on command line',CR,LF
  1792.                Db '  During normal use - ',CR,LF
  1793.                Db '             \ - switch to specific path',CR,LF
  1794.                Db '             / - search below subdirectory',CR,LF
  1795.                Db '                 these switches can be mixed',CR,LF
  1796.                Db '                 ie. sd \turbo/source\myprog would be legal',CR,LF,CR,LF
  1797.                Db '             @  - switch to last path selected with "#',CR,LF
  1798.                Db '             @" - kill SD and release memory',CR,LF
  1799.                Db '             "+ or -   - go to next highest or lowest path',CR,LF
  1800.                Db '             "#=[path] - store [path] in stack location #',CR,LF
  1801.                Db '             "#=@      - insert current path into stack location #',CR,LF
  1802.                Db '             "# - switch to entry number #',CR,LF
  1803.                Db '             "s - display stack',CR,LF,Stopper
  1804.  
  1805.  
  1806. ProgramEndH    Equ  $
  1807. PEH_Para       Equ  (ProgramEndH+15)/16
  1808.  
  1809.  
  1810.  
  1811.